package com.fengyunhe.common;

import com.fengyunhe.common.bean.PermTreeNode;
import com.fengyunhe.common.bean.TreeNode;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import java.io.FileNotFoundException;
import java.util.*;

/**
 * 功能：支持根据RootApplicationContext中的情况配置动态加载SPRINGMVC配置文件
 * 作者： yangyan
 * 时间： 2014/8/29 .
 */
public class AppDispatcherServlet extends DispatcherServlet {

    Logger log = LoggerFactory.getLogger(AppDispatcherServlet.class);

    @Override
    protected void onRefresh(ApplicationContext context) {
        super.onRefresh(context);
        //构建后台菜单树
        this.initModules(context);
    }


    /**
     * 根据情况动态修改配置文件路径
     *
     * @param wac
     */
    @Override
    protected void postProcessWebApplicationContext(ConfigurableWebApplicationContext wac) {
        super.postProcessWebApplicationContext(wac);
        String origin = getContextConfigLocation();
        WebApplicationContext webApplicationContext = (WebApplicationContext) this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        Map<String, AppModule> modules = webApplicationContext.getBeansOfType(AppModule.class);
        Set<String> strings = modules.keySet();

        for (String id : strings) {
            AppModule module = modules.get(id);
            module.setId(id);
        }
        List<String> configFile = new ArrayList<String>();
        configFile.add(origin);

        for (String id : strings) {
            AppModule module = modules.get(id);
            if (!module.isEnable()) { //没有开启
                continue;
            }
            try {
                sortConfigFile(null, configFile, module);
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }

        }
        wac.setConfigLocation(StringUtils.join(configFile, ","));
    }

    public void sortConfigFile(AppModule bigModule, List<String> list, AppModule module) throws Exception {
        if (!module.isEnable()) {
            if (bigModule == null) {
                throw new Exception("依赖的模块“" + module.getName() + "”被禁用，启动失败");
            } else {
                throw new Exception("“" + bigModule.getName() + "”依赖的模块“" + module.getName() + "”被禁用，启动失败");
            }
        }
        if (!module.isInited()) {
            module.setInited(true);
            String moduleConfigFile = "classpath:" + module.getId() + ".xml";

            try {
                ResourceUtils.getFile(moduleConfigFile);
            } catch (FileNotFoundException e) {
                log.error("模块“" + module.getName() + "”的配置文件“" + moduleConfigFile + "”不存在，该模块启动失败！");
                return;
            }

            if (bigModule != null) {
                String bigModuleConfigFile = "classpath:" + bigModule.getId() + ".xml";
                list.add(list.indexOf(bigModuleConfigFile), moduleConfigFile);
            } else {
                list.add(moduleConfigFile);
            }
            if (module.getDepend() != null && !module.getDepend().isEmpty()) {
                for (AppModule dept : module.getDepend()) {
                    sortConfigFile(module, list, dept);
                }
            }
        }
    }

    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

    private void initModules(ApplicationContext context2) {
        WebApplicationContext context = (WebApplicationContext) this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        //加载其他模块
        Map<String, AppModule> modules = context.getBeansOfType(AppModule.class);
        Collection<AppModule> values = modules.values();
        List<AppModule> moduleList = new ArrayList<AppModule>(values);
        Collections.sort(moduleList, new Comparator<AppModule>() {
            @Override
            public int compare(AppModule o1, AppModule o2) {
                return AppDispatcherServlet.compare(o1.getOrder(), o2.getOrder());
            }
        });
        for (AppModule module : moduleList) {
            if (!module.isEnable()) { //没有开启
                continue;
            }
            log.info("module " + module.getName() + " started..");
            String managementNodeBeanId = module.getId() + "ManagementNode";
            if (context2.containsBean(managementNodeBeanId)) {
                ManagementNode mNode = context2.getBean(managementNodeBeanId, ManagementNode.class);
                // 注册后台菜单权限和菜单树
                TreeNode modulePermsTreeNode = convertManagementPermsToTreeNode(mNode);
                AppContext.moduleManagementPermsTreeNodeList.add(modulePermsTreeNode);
                AppContext.managementNodeList.add(mNode);
            }

        }

    }

    /**
     * 转换后台管理权限为树节点
     *
     * @param managementNode
     * @return
     */
    private TreeNode convertManagementPermsToTreeNode(ManagementNode managementNode) {
        TreeNode moduleNode = new TreeNode();
        moduleNode.setText(managementNode.getName() + (StringUtils.isBlank(managementNode.getComment()) ? "" : "[" + managementNode.getComment() + "]"));
        moduleNode.setType("module");
        moduleNode.setId(managementNode.getFullId());
        moduleNode.setChecked(null);
        if (managementNode.getPermissions() != null) {
            for (ModulePermission p : managementNode.getPermissions()) {
                PermTreeNode perm = new PermTreeNode();
                perm.setText(p.getName());
                perm.setId(managementNode.getFullId() + ":" + p.getCode());
                perm.setType("perm");
                perm.setChecked(false);
                perm.setLeaf(true);
                moduleNode.addChildren(perm);
            }
        }
        if (managementNode.getChildren() != null && !managementNode.getChildren().isEmpty()) {
            for (ManagementNode subManagementNode : managementNode.getChildren()) {
                subManagementNode.parent = managementNode;
                moduleNode.addChildren(this.convertManagementPermsToTreeNode(subManagementNode));
            }
        }
        if (moduleNode.getChildren() != null) {
            moduleNode.setExpanded(true);
            moduleNode.setLeaf(false);
        } else {
            moduleNode.setLeaf(true);
        }
        return moduleNode;
    }
}
